'''
游戏需要窗口化（1600x900），最前面窗口

'''

import pyautogui
import pydirectinput
import time
import keyboard
import pygetwindow #兼容旧代码
import pygetwindow as gw
import ctypes
import win32gui
import win32con
import random
import sys
import io
import ctypes
import os
import fileinput
import subprocess
import progressbar
import threading
import datetime
from PIL import ImageGrab,Image
import utils
#游戏基本信息
game_title = '绝区零'
file_path = r'D:\miHoYo Launcher\games\ZenlessZoneZero Game\ZenlessZoneZero.exe'

# 窗口位置，游戏启动后获取
x1 = 0
y1 = 0
zzz = 0
#每一轮战斗分配的时间 s （根据自己账号练度调整）
fight_time_max = 330
fighting = False

def r():
    random_number = random.uniform(0.7, 0.9)
    time.sleep(random_number)
def rr():
    random_number = random.uniform(1.5, 2.0)
    time.sleep(random_number)
def rrr():
    time.sleep(15)
def sleep(t):
    time.sleep(t)#单位=秒
def click(x,y):
    pydirectinput.click(x+x1, y+y1)#点击
    rr()
def press(m):
    pydirectinput.press(m)#按键
    rr()
def long_press(m):
    # pydirectinput.press(m)#按键
    pydirectinput.keyDown(m)
    sleep(1)
    pydirectinput.keyUp(m)
    rr()
def getpngfromShot2(png,_threshold=0.8,_show_print=True):
    small = Image.open(f"zzz/{png}.png")
    big = pyautogui.screenshot(region=[x1,y1,xing.width,xing.height])
    point = utils.getpngfromShot(small,big,_threshold=_threshold)
    if _show_print:
        print(png,point)
    return point
def make_window_active(window_title):
    try:
        # 获取当前活动窗口的句柄
        foreground_window = win32gui.GetForegroundWindow()

        # 获取目标窗口
        windows = gw.getWindowsWithTitle(window_title)
        if not windows:
            print(f"No windows found with title '{window_title}'.")
            return False
        
        target_window = windows[0]._hWnd  # 获取第一个匹配窗口的句柄
        
        # 判断目标窗口是否为当前活动窗口
        if foreground_window == target_window:
            print(f"Window '{window_title}' is already the active window.")
            return True
        
        # 将窗口设置为活动窗口
        win32gui.ShowWindow(target_window, win32con.SW_RESTORE)  # 恢复窗口（如果它被最小化）
        win32gui.SetForegroundWindow(target_window)  # 设置为前景窗口
        
        print(f"Window '{window_title}' has been set as the active window.")
        return True
    except Exception as e:
        print(f"Error: {e}")
        return False
def is_window_active(window_title):
    try:
        # 获取当前活动窗口的句柄
        foreground_window = ctypes.windll.user32.GetForegroundWindow()

        # 获取所有窗口
        windows = pygetwindow.getWindowsWithTitle(window_title)
        if not windows:
            print(f"No windows found with title '{window_title}'.")
            return False

        # 获取目标窗口的句柄
        target_window = windows[0]._hWnd  # 获取第一个匹配窗口的句柄
        
        # 判断目标窗口是否为当前活动窗口
        if foreground_window == target_window:
            print(f"Window '{window_title}' is the active window.")
            return True
        else:
            print(f"Window '{window_title}' is not the active window.")
            return False
    except Exception as e:
        print(f"Error: {e}")
        return False
def move_XY(window_title,new_x,new_y):
    try:
        # 获取窗口对象
        windows = pygetwindow.getWindowsWithTitle(window_title)
        if not windows:
            print(f"No windows found with title '{window_title}'.")
            return
        
        # 选择第一个匹配的窗口
        window = windows[0]
        hwnd = window._hWnd

        # 获取当前窗口的位置信息
        rect = window._rect
        current_width = rect.width
        current_height = rect.height

        # 使用 ctypes 调用 MoveWindow API 移动窗口
        ctypes.windll.user32.MoveWindow(hwnd, new_x, new_y, current_width, current_height, True)
        print(f"Window '{window_title}' moved to ({new_x}, {new_y}) while keeping its size.")
    except Exception as e:
        print(f"Error: {e}")
def getXY():
    #init
    global game_title
    
    while(True):
        make_window_active(game_title)
        sleep(0.5)
        if is_window_active(game_title):
            sleep(0.5)
            move_XY(game_title,0,0)
            break

    # 获取指定标题的程序窗口对象
    program_window = pygetwindow.getWindowsWithTitle(game_title)[0]
    # 获取窗口左上角的位置
    top_left_position = program_window.topleft
    print(top_left_position)
    global x1,y1,xing;
    x1 = top_left_position.x
    y1 = top_left_position.y
    xing = program_window

# 进度条
def getBar(_maxval):
    bar = progressbar.ProgressBar(maxval=_maxval, widgets=[
        progressbar.Bar('=', '[', ']'), ' ', progressbar.Percentage()
    ])
    bar.start()
    return bar
def map(place,street):
    press("m") # 打开地图
    while True:
        loc = getpngfromShot2(place,_threshold=0.6)
        if loc!=0:
            break
        click(1155,408) # 下一个地址
        sleep(1)
    if street=="报刊亭":
        click(910,848)
    elif street=="咖啡店":
        click(426,848)
    elif street=="HIA俱乐部":
        click(801,848)
    elif street=="柜台":
        # click(679,859)
        click(804,861) #V1.2更新的坐标
    click(936,550) # 确认传送

    print("等待传送")
    bar = getBar(30)
    for i in range(30):
        sleep(1) #等待游戏启动
        bar.update(i)
        # press("tab")
        loc = getpngfromShot2("星期",_show_print=False)
        if loc!=0:
            break
    bar.finish()

    print("传送完毕")   
def fight():
    while fighting:
        pydirectinput.keyDown("q")
        pydirectinput.keyDown("w")
        pydirectinput.keyDown("e")
        pydirectinput.keyDown("space")
        pydirectinput.mouseDown(button='left')
        pydirectinput.keyUp("q")
        pydirectinput.keyUp("w")
        pydirectinput.keyUp("e")
        pydirectinput.keyUp("space")
        pydirectinput.mouseUp(button='left')

def eighteen():
    sleep(2)
    map("Random_Play","柜台")
    long_press("w")
    # press("a")
    press("f")
    sleep(3)
    click(1143,232) #关闭上个页面
    click(755,664) #选择宣传员
    click(1433,897) #确定
    click(997,664) #第一本杂志
    click(543,269) #第一本杂志
    click(1422,892) #上架
    click(718,268) #第二本杂志
    click(1422,892) #上架
    click(878,270) #第三本杂志
    click(1422,892) #上架
    click(101,79) # 左上角返回
    click(1395,847) #开始营业
    click(939,554) #确定
    press("esc")
    press("esc")
def newsstand():
    sleep(2)
    map("六分街","报刊亭")

    long_press("w")
    # press("d")
    # press("d")
    press("f")
    sleep(1)
    click(123,824)#左下角小彩票
    #TODO 夜间要先叫醒他
    loc = getpngfromShot2("叫醒他")
    if loc!=0:
        click(loc[0],loc[1])
        sleep(1)
        click(500,500)
        sleep(1)
        click(123,824)#左下角小彩票
    
    
    #刮彩票
    pyautogui.moveTo(x1+658,y1+470)
    pyautogui.mouseDown()
    pyautogui.moveTo(x1+957,y1+491,duration=1)
    pyautogui.moveTo(x1+662,y1+511,duration=1)
    pyautogui.moveTo(x1+953,y1+527,duration=1)
    pyautogui.moveTo(x1+662,y1+545,duration=1)
    pyautogui.moveTo(x1+961,y1+574,duration=1)
    pyautogui.mouseUp()

    click(813,641) # 确认按钮
    press("esc")
    press("esc")
def coffee():
    sleep(2)
    map("六分街","咖啡店")
    press("f")
    sleep(3)
    #左滑
    pyautogui.moveTo(x1+780,y1+755)
    pyautogui.mouseDown()
    pyautogui.moveTo(x1+340,y1+755,duration=1)
    pyautogui.mouseUp()
    sleep(1)
    '''
    loc = getpngfromShot2("新艾利都特调")
    if loc!=0:
        click(loc[0],loc[1]) 
    else:
        loc = getpngfromShot2("新艾利都特调2",_threshold=0.5)
        if loc!=0:
            click(loc[0],loc[1])  
        else:
            print("没找到 新艾利都特调 咖啡")
            press("esc")
            return
    '''
    click(1499,863) # 点单
    click(923,552) # 确认
    sleep(20)
    # click(1480,145) # 跳过 #TODO
    click(800,635) # 确认
def materials():
    sleep(2)
    global fighting
    
    map("协会俱乐部","HIA俱乐部")

    print("和左边的小姐姐对话")
    long_press("w")
    press("a")
    press("a")
    press("f")
    click(1200,853)
    click(1290,584)
    sleep(2)

    print("打自定义通用材料")
    # click(1200,435) # 自定义模版
    print("寻找 自定义模版")
    bar = getBar(30)
    for i in range(30):
        loc = getpngfromShot2("自定义模版",_threshold=0.9)
        if loc!=0:
            click(loc[0],loc[1])
            break;
        sleep(1)
    bar.finish()

    moban = 236 # 第一个模版
    while True:
        # TODO 体力不够的情况
        while True:
            if moban>1535: 
                print("体力打完了")
                press("esc")
                press("esc")
                return 0 #出口
            click(moban,703) # 第 moban 个模版
            click(1439,890) # 下一步
            loc = getpngfromShot2("恢复电量")
            if loc!=0:
                press("esc")
                moban+= 290 #103 393
            else:break;
        sleep(2)
        click(1439,890) # 出站
        sleep(5) #等待进入战斗
        print("进入战斗。。。")
        bar = getBar(90)
        fighting = True
        fight_thread = threading.Thread(target=fight)
        fight_thread.start()
        for i in range(90):
            sleep(1)
            bar.update(i)
            loc = getpngfromShot2("挑战结果",_show_print=False)
            if loc !=0:
                break
        fighting = False
        fight_thread.join()
        click(1422,886) # 完成按钮
        bar.finish()
        # sleep(5) # 等待返回自定义模版（可能返回 今晚休息）
        # TODO 今晚休息的提示 概率性的
        print("检测是否触发：今晚休息")
        bar = getBar(10)
        for i in range(10):
            bar.update(i)
            loc = getpngfromShot2("今晚休息",_show_print=False)
            if loc!=0:
                for j in range(3):
                    click(loc[0],loc[1])
                    sleep(2)
                #materials() #重新 打材料
                return -1
                break;
            sleep(1)
        bar.finish()

        # sleep(5) # 等待返回自定义模版（可能返回 今晚休息）检测 
        # 检测 今晚休息 的时间足够退出了。就不需要等待退出了
        # bar = getBar(20)
        # for i in range(20):
        #     bar.update(i)
        #     loc = getpngfromShot2("挑战奖励",_show_print=False)
        #     if loc!=0:break;
        #     sleep(1)
        # bar.finish()
def daily():
    sleep(2)
    press("f2")
    click(938,169) #日常
    click(636,265) #第一个活跃度
    press("esc")
    press("esc")
def ceremony():
    sleep(2)
    press("f3")
    sleep(1)
    loc = getpngfromShot2("城募赠礼")
    if loc==0:
        print("没有 城募赠礼")
        return
    click(1260,76) #成长任务
    click(1434,890) #全部领取
    # click(1062,73) #等级回馈
    # click(1117,895) #全部领取
    # press("esc")
    press("esc")

def drive():
    # sleep(2)
    global fighting
    press("f2")
    click(1127,173) #训练
    click(300,443) #定期清剿
    # target = "锐牙与钝斧"
    target = "恶拳与凶枪"
    max_wheel = 0
    while(max_wheel < 4):
        sleep(0.5)
        point = getpngfromShot2(target)
        if point!=0:
            click(point[0]+700,point[1]+50) #前往
            click(946,556) #确认
            bar = getBar(20)
            for i in range(20):
                sleep(1)
                bar.update(i)
                point = getpngfromShot2("挑战等级",_show_print=False)
                if point!=0:
                    break;
            bar.finish()
            click(1435,891) #下一步
            point = getpngfromShot2("恢复电量")
            if point==0:
                click(1435,891) #出战
                sleep(5)
                print("进入战斗。。。")
                bar = getBar(90)
                fighting = True
                fight_thread = threading.Thread(target=fight)
                fight_thread.start()
                for i in range(90):
                    sleep(1)
                    bar.update(i)
                    loc = getpngfromShot2("挑战结果",_show_print=False)
                    if loc !=0:
                        break
                fighting = False
                fight_thread.join()
                click(1422,886) # 完成按钮
                bar.finish()
                bar = getBar(20)
                for i in range(20):
                    sleep(1)
                    bar.update(i)
                    point = getpngfromShot2("挑战等级",_show_print=False)
                    if point!=0:
                        break;
                bar.finish()
                press("esc")
            else:
                print("体力不够60，刷不了 驱动盘")
                press("esc")
                press("esc")
                return -1
            break;
        else:
            pyautogui.moveTo(x1+672,y1+485) 
            for i in range(1):
                pyautogui.scroll(-100)
            max_wheel+=1

def weekly(boss):
    sleep(2)
    press("f2")
    click(1263,176) #挑战
    click(277,345) #恶名狩猎
    click(1213,399) #初生死路屠夫 前往
    click(928,557) #确认
    for i in range(20):
        sleep(1)
        loc =getpngfromShot2(boss,_show_print=False)
        if loc!=0:
            click(loc[0],loc[1]+100)
            break
    click(1425,894) #下一步
    click(1425,894) #出站
    for i in range(20):
        sleep(1)
        loc =getpngfromShot2("space",_show_print=False)
        if loc!=0:
            break
    press("a")
    press("a")
    press("a")
    press("a")
    long_press("w")
    press("f")
    click(459,697) #选择第一个卡片
    
    long_press("w")
    global fighting
    bar=getBar(180)
    fighting = True
    fight_thread = threading.Thread(target=fight)
    fight_thread.start()
    for i in range(180):
        sleep(1)
        bar.update(i)
        loc = getpngfromShot2("挑战结果",_show_print=False)
        if loc !=0:
            sleep(1)
            break
    fighting = False
    fight_thread.join()
    bar.finish()
    click(1421,891) #完成
    for i in range(20):
        sleep(1)
        loc = getpngfromShot2("街区",_show_print=False)
        if loc!=0:
            break
    press("esc")
    press("esc")
def get_weekly_award():
    sleep(2)
    press("f2")
    click(1263,176) #挑战
    click(277,345) #恶名狩猎
    click(1213,399) #初生死路屠夫 前往
    click(928,557) #确认
    for i in range(20):
        sleep(1)
        loc =getpngfromShot2("初生死路屠夫",_show_print=False)
        if loc!=0:
            break
    click(110,873) #左下角奖励
    click(1086,337) #全部领取
    press("esc")
    press("esc")
    press("esc")


def old_capital_train():
    sleep(2)
    press("f2")
    click(1257,162) #挑战
    click(267,430) #零号空洞
    click(1210,714) #旧都列车 前往按钮
    click(926,555) #确认按钮
    
    first = 0
    second = 0
    while True:
        print(f"第{first+1}次挑战旧都列车。。。")
        sum = checkCell()
        if sum ==1:
            first += 1
            print(f"first={first}")
        elif sum == 2:
            second += 1
            print(f"second={second}")
        if first == 45:
            print(f"finish 45===,first={first},second={second}")
            break
    
    press("esc") #退出到主页面
def checkCell():
    for i in range(10):
        loc =getpngfromShot2("旧都列车",_show_print=False)
        if loc!=0:
            click(loc[0],loc[1])
            break
        sleep(1)
    click(1207,359) #旧都列车·前线
    click(1422,894) #下一步
    click(1422,894) #出战
    click(934,556) #携带队员数量较少时，确认出击
    bar = getBar(90)
    for i in range(20):
        bar.update(i)
        loc =getpngfromShot2("假面研究者",_show_print=False)
        if loc!=0:
            sleep(1)
            click(loc[0],loc[1])
            click(loc[0],loc[1])
            click(1234,600) #拒绝他的好意
            click(loc[0],loc[1])
            click(loc[0],loc[1])
            break
        sleep(1)
    bar.finish()

    print("进入格子。。。")
    sleep(5)
    press("s")
    for i in range(10):
        loc = getpngfromShot2("呼叫增援")
        if loc!=0:
            click(loc[0],loc[1])
            click(1216,508) #接应增援
            click(1216,480) #二号位
            click(800,550) # 确认
            break
        else: # TODO 没有 呼叫增援就退出处理
            for i in range(10):
                loc = getpngfromShot2("space",_show_print=False)
                if loc!=0:
                    press("esc")
                    click(1426,881) #退出战斗
                    click(923,558) #确认
                    sleep(8)
                    click(1426,881) #完成
                    return 2 #不是第一种地图，返回重来

    global fighting
    print("第一阶段战斗。。。")
    press("s")
    for i in range(20):
        sleep(1)
        loc = getpngfromShot2("space")
        if loc!=0:
            loc = getpngfromShot2("m")
            if loc!=0:
                if loc[0]<800:
                    sleep(2)
                    long_press("w")
                    long_press("w")
                    long_press("a")
                    long_press("w")
                    long_press("a")
                elif loc[0]>800:
                    sleep(2)
                    long_press("w")
                    long_press("w")
                    long_press("d")
                    long_press("w")
                    long_press("d")
            break 
    bar = getBar(90)
    # sleep(3)
    # long_press("w")
    fighting = True
    fight_thread = threading.Thread(target=fight)
    fight_thread.start()
    flag = 0
    for i in range(90):
        sleep(1)
        bar.update(i)
        loc = getpngfromShot2("卡片选择",_show_print=False)
        if loc !=0:
            flag = 1
            break
    fighting = False
    fight_thread.join()
    bar.finish()
    if flag==1:
        click(796,695) # 完成后直接到 卡片选择
    else:
        print("第一阶段战斗 意外。。。")
        press("esc")
        click(1426,881) #退出战斗
        click(923,558) #确认
        sleep(8)
        click(1426,881) #完成
        return 2
    
    print("第二阶段战斗。。。")
    press("d")
    sleep(2)
    press("d")
    sleep(2)
    click(1196,510) #确认继续
    for i in range(20):
        sleep(1)
        loc = getpngfromShot2("space",_show_print=False)
        if loc!=0:
            loc = getpngfromShot2("m")
            if loc!=0:
                if loc[0]<800:
                    sleep(2)
                    long_press("w")
                    long_press("w")
                    long_press("a")
                    long_press("w")
                    long_press("a")
                elif loc[0]>800:
                    sleep(2)
                    long_press("w")
                    long_press("w")
                    long_press("d")
                    long_press("w")
                    long_press("d")
            break 
    bar = getBar(90)
    # sleep(3)
    # long_press("w")
    fighting = True
    fight_thread = threading.Thread(target=fight)
    fight_thread.start()
    flag = 0
    for i in range(90):
        sleep(1)
        bar.update(i)
        loc = getpngfromShot2("挑战结果2",_show_print=False)
        if loc !=0:
            sleep(1)
            flag = 1
            break
    fighting = False
    fight_thread.join()
    bar.finish()
    if flag==1:
        click(954,848) # 挑战结果2 确认
        click(796,695) # 卡片选择
    else:
        print("第二阶段战斗 意外。。。")
        press("esc")
        click(1426,881) #退出战斗
        click(923,558) #确认
        sleep(8)
        click(1426,881) #完成
        return 2

    print("第二位面。。。") # TODO 多有选择情况
    sleep(5)
    press("w")
    sleep(1)
    click(1108,329)
    click(1108,329)
    click(1108,329)
    click(1108,329)
    click(1108,329)
    # click(1167,645) #第三个选项
    # click(801,641) #确认
    print("随机选项:")
    loc = getpngfromShot2("恢复身体",_show_print=False)
    if loc !=0:
        click(loc[0],loc[1])
    loc = getpngfromShot2("拿点垃圾物资",_show_print=False)
    if loc !=0:
        click(loc[0],loc[1])
        click(809,693) #确定
    loc = getpngfromShot2("帮我催化催化鸣微",_show_print=False)
    if loc !=0:
        click(loc[0],loc[1])
        sleep(2)
        click(809,693) #确定
        sleep(2)
        click(809,693) #确定 TODO 不一定有第二个确定
        
    click(1108,329)
    sleep(1)
    press("d")
    press("w")
    press("w")
    press("d")
    press("d")
    sleep(1)
    click(1108,329)
    click(1108,329)
    sleep(3)
    press("d")
    press("w")
    click(801,641) #确认
    print("完成任务。。。退出")
    press("esc")
    click(1424,892) #放弃
    click(926,555) #确认
    sleep(5)
    click(1424,892) #完成
    sleep(10)
    return 1

    


def launch_game():
    sleep(2)
    global file_path
    #C:\Program Files\Star Rail\Game\StarRail.exe
    game_name = os.path.basename(file_path)
    call = 'TASKLIST','/FI',f'imagename eq {game_name}'
    output = subprocess.check_output(call).decode('cp1252')
    if game_name in output:
        isLaunchGame = True
    else:
        isLaunchGame = False
    
    #isLaunchGame = True
    if not isLaunchGame:
        print("not running")
        try:
            # 调用subprocess模块来启动.exe文件
            # subprocess.Popen(file_path,creationflags=subprocess.CREATE_NEW_CONSOLE)
            game_process = subprocess.Popen(['start', '', file_path], shell=True)
            result = 1
        except FileNotFoundError as e:
            print("未能找到指定的.exe文件")
            result = 0
        except Exception as e:
            print("发生错误：", str(e))
            result = 0
            
        if(result == 0):
            print("脚本结束...")
            exit()
        else:
            print("等待游戏启动...")
            bar=getBar(60)

            #启动程序到加载窗口出来
            for i in range(60):
                #print(str(i)+"-",end="")
                sleep(1) #等待游戏启动
                bar.update(i)
                if any(game_title in win.title for win in pygetwindow.getWindowsWithTitle(game_title)):
                    break
            bar.finish()

            #初始化位置，将程序放到左上角
            getXY()

            print("窗口加载开机动画，等待 点击进入游戏 按钮")
            bar.start()
            flag_again = 0
            for i in range(30):
                sleep(1) #等待游戏启动
                bar.update(i)
                loc = getpngfromShot2("点击进入游戏",_show_print=False)
                if loc!=0:
                    flag_again+=1
                if flag_again>4:
                    break
                # click(500,500)
            # sleep(20)
            bar.finish()
            click(500,500) # 点击进入游戏

            #点击进入游戏 到 游戏画面
            print("点击进入游戏 到 游戏画面")
            bar.start()
            for i in range(30):
                sleep(1) #等待游戏启动
                bar.update(i)
                # press("tab")
                loc = getpngfromShot2("剩余",_show_print=False)
                if loc!=0:# TODO other 界面
                    click(631,698)
                    click(826,693)
                    click(1014,693)
                    click(1210,693)
                    click(1443,693)
                    click(814,644) #确定
                    click(102,69) #左上角返回按钮
                    # break
                loc = getpngfromShot2("队员界面",_show_print=False)
                if loc!=0:
                    break
                # click(500,500)
            # sleep(20)
            bar.finish()

            print("游戏加载完毕。。。")        
    else:
        print("running")
        getXY()

def test():
    sleep(2)
    

def play():
    print("启动游戏。。。")
    launch_game()

    print("18号。。。")
    eighteen()

    print("喝咖啡")
    coffee()

    # print("刷驱动盘")
    # while drive()!=-1:pass

    print("刷材料")
    while materials()==-1:pass    

    print("领取日常活跃度")
    daily()

    print("城募赠礼")
    ceremony()

    print("报刊。。。")
    newsstand()

    # today = datetime.datetime.today()
    # if today.weekday() == 6:
    #     sleep(1)
    #     print("周本。。。")
    #     weekly("初生死路屠夫")
    #     weekly("初生死路屠夫")
    #     weekly("未知复合侵蚀体")
    #     get_weekly_award()

        # print("旧都列车-前线")  
        # old_capital_train()




# main
if __name__ == "__main__":

    admin = ctypes.windll.shell32.IsUserAnAdmin()
    print("admin=="+str(admin))

    if admin:
        print("have admin")
        # 主程序写在这里
        try:
            play()
        except Exception as e:
            print(e)

        # input() # 防止退出
    else:
        print("not admin")
        # 以管理员权限重新运行程序
        if len(sys.argv) > 1:
            ctypes.windll.shell32.ShellExecuteW(None,"runas", sys.executable, __file__+" "+sys.argv[1], None, 3)
        else:
            ctypes.windll.shell32.ShellExecuteW(None,"runas", sys.executable, __file__, None, 3)




















